﻿using log4net;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using System.Reflection;

namespace flyfire.whitelistAuthorization.Controllers
{
    [ApiController]
    [Route("api/[controller]")]
    public class WhitelistController : ControllerBase
    {
        private readonly WhiteIpList _whiteIpList;
        //private static readonly ILog log = LogManager.GetLogger(typeof(WhitelistController));
        private readonly ILogger<WhitelistController> _logger;
        public WhitelistController(IOptions<WhiteIpList> whiteIpList, ILogger<WhitelistController> logger)
        {
            _whiteIpList = whiteIpList.Value;
            _logger = logger;
        }

        [HttpGet("[action]")]
        [HttpPost("[action]")]
        public IActionResult Authorization()
        {
            var remote_ip = GetClientIpAddress(HttpContext.Request);
            var ip_find = Untility.IsIpExist(_whiteIpList.IpList, remote_ip);

            //log.Debug($"{MethodBase.GetCurrentMethod().Name} check remote Ip: {remote_ip}: {ip_find}");
            _logger.LogDebug($"_logger {MethodBase.GetCurrentMethod().Name} check remote Ip: {remote_ip}: {ip_find}");

            if (ip_find)
            {
                return Ok(new
                {
                    body = new
                    {
                        code = 200
                    }
                });
            }
            else
            {
                return StatusCode(401, "Unauthorized: IP address not in whitelist.");
            }
        }

        [HttpGet("[action]")]
        public IActionResult GetClientIpAddress()
        {
            return Ok(new
            {
                body = new
                {
                    ip = GetClientIpAddress(HttpContext.Request)
                }
            });
        }

        [HttpGet("[action]")]
        public IActionResult GetWhitelist()
        {
            var remote_ip = GetClientIpAddress(HttpContext.Request);
            var ip_find = Untility.IsIpExist(_whiteIpList.IpList, remote_ip);

            //log.Debug($"{MethodBase.GetCurrentMethod().Name} check remote Ip: {remote_ip}: {ip_find}");
            _logger.LogDebug($"_logger {MethodBase.GetCurrentMethod().Name} check remote Ip: {remote_ip}: {ip_find}");

            if (ip_find)
            {
                return Ok(new
                {
                    body = new
                    {
                        _whiteIpList.IpList
                    }
                });
            }
            else
            {
                return StatusCode(401, "Unauthorized: IP address not in whitelist.");
            }
        }

        private string GetClientIpAddress(HttpRequest request)
        {
            /*
            如果认证服务接口需经过Nginx转发时，则需要对Nginx进行一些配置以及相应的代码处理方可有效获取到浏览端的IP。
            当网络HTTP请求经过Nginx服务器转发时，Web API仍然有可能获取到请求方的IP地址，但这取决于Nginx的配置以及Web API如何解析这些信息。 
            Nginx配置
            Nginx可以通过proxy_set_header指令来添加或修改转发给后端服务器的请求头。为了获取请求方的IP地址，你需要在Nginx配置文件中设置X-Forwarded-For请求头，该请求头会包含客户端的原始IP地址。
            例如，你可以在Nginx的配置文件（通常是nginx.conf或某个站点的配置文件）的反向代理段中添加以下行：

               proxy_set_header X-Forwarded-For $remote_addr;

            这行代码会将客户端的IP地址添加到X-Forwarded-For请求头中，并将其转发给后端服务器。
            如果客户端和Nginx之间有多层代理，X-Forwarded-For请求头可能会包含多个IP地址，第一个地址通常是客户端的原始IP。
            */

            // 首先尝试从X-Forwarded-For请求头中获取IP地址
            var xForwardedFor = request.Headers["X-Forwarded-For"].ToString();
            if (!string.IsNullOrEmpty(xForwardedFor))
            {
                // 如果X-Forwarded-For包含多个IP地址，取第一个地址作为客户端IP
                var ipAddresses = xForwardedFor.Split(',');
                return ipAddresses.FirstOrDefault()?.Trim();
            }

            // 如果X-Forwarded-For不存在，则尝试从RemoteAddress属性中获取IP地址
            return request.HttpContext.Connection.RemoteIpAddress?.ToString();
        }
    }

    public class Untility
    {
        public static bool IsIpExist(List<string> IpList, string req_src)
        {
            foreach (var ip in IpList)
            {
                if (req_src.Contains(ip))
                    return true;
            }
            return false;
        }
    }
}
